<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    html,
    body {
      padding: 0;
      margin: 0;
    }
  </style>
  <!-- 顶点着色器 定义代码 -->
  <script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_position;
    uniform vec2 u_resolution;

    void main() {
      // 从像素坐标转换为0.0 - 1.0
      vec2 zeroToOne = a_position.xy / u_resolution;
      vec2 zeroToTwo = zeroToOne * 2.0;
      vec2 clipSpace = zeroToTwo - 1.0;

      // clipSpace: y 轴起点在左下角
      // vec2(1, -1): 翻转 y 轴
      gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
    }
  </script>
  <!-- 片元着色器 定义代码 -->
  <script id="fragmentShader" type="x-shader/x-fragment">
    precision mediump float;

    uniform vec4 u_color;
    void main() {
      gl_FragColor = u_color;
    }
  </script>
</head>
<body>
<canvas id="canvas" width="600" height="450"></canvas>
<script>

var gl = null;
function init () {
  var canvas = document.getElementById('canvas');
  gl = canvas.getContext('webgl');

  var vertexShaderSource = getShaderSource('#vertexShader')
  var fragmentShaderSource = getShaderSource('#fragmentShader')

  var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
  var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

  var program = createProgram(gl, vertexShader, fragmentShader);

  var positionBuffer = gl.createBuffer();
  var positionAttrLocal = gl.getAttribLocation(program, 'a_position');
  var resolutionUniformLocation = gl.getUniformLocation(program, 'u_resolution');
  var colorUniformLocation = gl.getUniformLocation(program, 'u_color');

  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

  gl.viewport(0, 0, window.innerWidth, window.innerHeight);

  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.useProgram(program);

  gl.enableVertexAttribArray(positionAttrLocal);

  gl.vertexAttribPointer(positionAttrLocal, 2, gl.FLOAT, false, 0, 0);

  // gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);

  for (var i = 0; i < 50; i++) {
    // gl.clear(gl.COLOR_BUFFER_BIT);
    // 四边形数据
    setRectangle(gl, randomInt(300), randomInt(300), randomInt(300), randomInt(300));
    // 四边形颜色
    gl.uniform4f(colorUniformLocation, Math.random(), Math.random(), Math.random(), 1);
    // 绘制四边形
    gl.drawArrays(gl.TRIANGLES, 0, 6);
  }

  /**
   * 返回一个指定长度的随机值
   * @param range
   * @returns {number}
   */
  function randomInt (range) {
    return Math.floor(Math.random() * range)
  }

  /**
   * 根据 指定坐标 & 长宽 创建矩形
   * @param gl
   * @param x
   * @param y
   * @param width
   * @param height
   */
  function setRectangle (gl, x, y, width, height) {
    var x1 = x;
    var x2 = x + width;
    var y1 = y;
    var y2 = y + height;

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
      x1, y1,
      x2, y1,
      x1, y2,
      x1, y2,
      x2, y1,
      x2, y2,
    ]), gl.STATIC_DRAW);
  }
}

/**
 * 获取着色器程序代码
 *
 * @param shaderId
 * @returns {string}
 */
function getShaderSource (shaderId) {
  var shaderScript = document.querySelector(shaderId);

  if (!shaderScript) {
    return ''
  }

  return shaderScript.textContent;
}

/**
 * 创建着色器
 *
 * @param gl 上下文
 * @param type 类型
 * @param source 数据源
 * @returns {*|WebGLShader}
 */
function createShader (gl, type, source) {
  // 创建着色器对象
  var shader = gl.createShader(type);

  // 提供数据源
  gl.shaderSource(shader, source);
  // 编译 -> 生成着色器
  gl.compileShader(shader);

  // 检查着色器是否编译成功
  var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);

  // 成功则返回着色器
  if (success) {
    return shader;
  }

  // 否则删除着色器
  gl.deleteShader(shader);
}

/**
 * 连接/关联两个作色器片段 到一个着色器程序
 *
 * @param gl
 * @param vertexShader
 * @param fragmentShader
 * @returns {WebGLProgram}
 */
function createProgram (gl, vertexShader, fragmentShader) {
  // 创建一个着色器程序
  var program = gl.createProgram();

  // 指定定点着色器
  gl.attachShader(program, vertexShader);
  // 指定片元着色器
  gl.attachShader(program, fragmentShader);
  // 关联着色器程序
  gl.linkProgram(program);

  // 检查着色器程序是否编译成功
  var success = gl.getProgramParameter(program, gl.LINK_STATUS);

  if (success) {
    return program;
  }

  gl.deleteProgram(program)
}

init();
</script>
</body>
</html>
